#pragma once
#include <iostream>
#include <sys/stat.h>
#include <sys/time.h>
#include <atomic>
#include<fstream>
#include<boost/algorithm/string.hpp>
#include<vector>

namespace ns_util
{
    const static std::string temp_path = "./temp/";

    class TimeUtil
    {
    public:
        static time_t GetTimeStamp()
        {
            struct timeval tv;
            gettimeofday(&tv, nullptr);
            return tv.tv_sec;
        }

        static time_t GetTimeMs()
        {
            struct timeval tv;
            gettimeofday(&tv, nullptr);
            return tv.tv_sec * 1000 + tv.tv_usec / 1000;
        }
    };

    class PathUtil
    {
        static std::string AddSuffix(const std::string &file_name, const std::string &suffix)
        {
            std::string path = temp_path;
            path += file_name;
            path += suffix;
            return path;
        }

    public:
        static std::string Src(const std::string &file_name)
        {
            return AddSuffix(file_name, ".cpp");
        }

        static std::string Exe(const std::string &file_name)
        {
            return AddSuffix(file_name, ".exe");
        }

        static std::string CompileErr(const std::string &file_name)
        {
            return AddSuffix(file_name, ".compile_err");
        }

        static std::string Stderr(const std::string &file_name)
        {
            return AddSuffix(file_name, ".stderr");
        }

        static std::string Stdin(const std::string &file_name)
        {
            return AddSuffix(file_name, ".stdin");
        }

        static std::string Stdout(const std::string &file_name)
        {
            return AddSuffix(file_name, ".stdout");
        }
    };

    class FileUtil
    {
    public:

        static bool IsFileExists(const std::string &path_name)
        {
            struct stat st;
            if (stat(path_name.c_str(), &st) == 0)
            {
                return true;
            }
            return false;
        }

        static std::string UniqFileName()
        {
            // 毫秒级时间戳+原子性唯一递增值
            static std::atomic_uint ui(0);
            ui++;
            std::string ms = std::to_string(TimeUtil::GetTimeMs());
            std::string unique_int = std::to_string(ui);
            return ms + "_" + unique_int;
        }

        static bool WriteCode(const std::string &target, const std::string &code)
        {
            std::ofstream out(target.c_str());
            if(!out.is_open())
            {
                return false;
            }
            out.write(code.c_str(),code.size());
        
            out.close();
            return true;
        }

        static bool ReadFile(const std::string &target,std::string* out, bool keep = false)
        {
            out->clear();
            std::ifstream in(target);
            if(!in.is_open())
            {
                return false;
            }
            std::string line;
            while(std::getline(in,line))
            {
                (*out) += line;
                (*out) += (keep ? "\n":"");
            }

            in.close();
            return true;
        }
    };

    class StringUtil
    {
    public:
        static void Splitstr(const std::string & str,std::vector<std::string> * out, const std::string& gap)
        {
            boost::split((*out),str,boost::is_any_of(gap) , boost::algorithm::token_compress_on);
        }

    };
}